package com.mkx.template;

import com.mkx.core.lock.RedisDistributedLock;
import com.mkx.core.monitor.RedisLockStats;
import com.mkx.properties.RedisLockProperties;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

public class RedisLockTemplate {
    
    private final RedisTemplate<String, Object> redisTemplate;
    private final RedisLockProperties properties;
    private final RedisLockStats stats;
    
    public RedisLockTemplate(RedisTemplate<String, Object> redisTemplate, 
                           RedisLockProperties properties) {
        this.redisTemplate = redisTemplate;
        this.properties = properties;
        this.stats = RedisLockStats.getInstance();
    }
    
    /**
     * 获取分布式锁
     */
    public RedisDistributedLock getLock(String lockKey) {
        String fullLockKey = properties.getPrefix() + lockKey;
        return new RedisDistributedLock(redisTemplate, fullLockKey, properties.getExpireTime());
    }
    
    /**
     * 使用锁执行任务
     */
    public <T> T executeWithLock(String lockKey, long waitTime, TimeUnit timeUnit, LockTask<T> task) {
        RedisDistributedLock lock = getLock(lockKey);
        boolean locked = false;
        long startTime = System.currentTimeMillis();
        
        try {
            // 记录获取锁开始
            stats.recordAcquireStart();
            
            if (lock.tryLock(waitTime, timeUnit)) {
                locked = true;
                long acquireTime = System.currentTimeMillis() - startTime;
                // 记录获取锁成功
                stats.recordAcquireSuccess(acquireTime);
                return task.execute();
            } else {
                // 记录获取锁失败
                stats.recordAcquireFailed();
                throw new LockAcquisitionException("Acquire lock timeout: " + lockKey);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new LockAcquisitionException("Lock interrupted: " + lockKey, e);
        } finally {
            if (locked) {
                try {
                    // 记录释放锁开始
                    stats.recordReleaseStart();
                    lock.unlock();
                    // 记录释放锁成功
                    stats.recordReleaseSuccess();
                } catch (Exception e) {
                    // 记录释放锁失败
                    stats.recordReleaseFailed();
                    throw e;
                }
            }
        }
    }
    
    /**
     * 使用默认等待时间执行任务
     */
    public <T> T executeWithLock(String lockKey, LockTask<T> task) {
        return executeWithLock(lockKey, properties.getWaitTime(), TimeUnit.MILLISECONDS, task);
    }
    
    /**
     * 异步执行任务
     */
    public <T> CompletableFuture<T> executeWithLockAsync(String lockKey, LockTask<T> task) {
        return CompletableFuture.supplyAsync(() -> 
            executeWithLock(lockKey, task)
        );
    }
    
    /**
     * 获取锁统计信息
     */
    public String getStats() {
        return stats.getStatsInfo().toString();
    }
    
    /**
     * 重置锁的统计信息
     */
    public void resetStats() {
        stats.resetStats();
    }
    
    /**
     * 锁任务接口
     */
    @FunctionalInterface
    public interface LockTask<T> {
        T execute();
    }
    

    /**
     * 自定义异常
     */
    public static class LockAcquisitionException extends RuntimeException {
        public LockAcquisitionException(String message) {
            super(message);
        }
        
        public LockAcquisitionException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}